Modify federation to be possible with edn schema as well - #420
Conversation
hlship
left a comment
There was a problem hiding this comment.
Thanks for the initial effort! I've outlined some improvements that could be made.
| org.flatland/ordered {:mvn/version "1.15.10"} | ||
| org.clojure/data.json {:mvn/version "2.4.0"}} | ||
| org.clojure/data.json {:mvn/version "2.4.0"} | ||
| org.clojure/core.match {:mvn/version "1.0.0"}} |
There was a problem hiding this comment.
Looking at how match is used in the code, it feels a bit like over kill - most of the cases could be covered with cond or condp, and adding dependencies is always an issue.
| @@ -0,0 +1,34 @@ | |||
| type _Service{ | |||
There was a problem hiding this comment.
I wonder if we could get pretty-printed output. It would make things more complicated, for sure.
There was a problem hiding this comment.
It's a bit complicated, but I'll try.
| [description] | ||
| (if (nil? description) | ||
| "" | ||
| (str "\"\"\"\n" description "\n\"\"\"\n"))) |
There was a problem hiding this comment.
What if description itself includes characters, such as ", that need to be escaped?
There was a problem hiding this comment.
The input is edn, so there seems to be no problem. Can you give me an example?
| (defn ^:private value->string | ||
| [value] | ||
| (match value | ||
| (string :guard string?) (str "\"" string "\"") |
There was a problem hiding this comment.
Same here, may need to escape some characters.
| (edn-directives->sdl-directives directives) | ||
| (edn-fields->sdl-fields fields)))) | ||
| (join "\n"))) | ||
| (defn ^:private edn-queries->sdl-queries |
There was a problem hiding this comment.
I prefer a blank line between def forms. There's a couple of cases of this.
There was a problem hiding this comment.
:queries is such a hold over from early days Lacinia; we really should deprecate it, it causes problems.
That being said, should probably fold :queries in the Query object (likewise mutations and subscriptions) and then pretty print that.
It may be ok to skimp on some error checking, such as name collisions between Query fields an names in the :queries map ... incorrect SDL will be generated BUT that will be caught an instant later at schema compilation and/or calls to prevent-collision.
| (defn ^:private edn-scalars->sdl-scalars | ||
| [scalars] | ||
| (->> (keys scalars) | ||
| (map name) |
There was a problem hiding this comment.
I think there's value to sorting by name in each of these blocks, for repeatability.
There was a problem hiding this comment.
Sorting has been added to reflect reviews.
| "Translate the edn lacinia schema to the SDL schema." | ||
| [schema] | ||
| (->> schema | ||
| (map (fn [[key val]] |
There was a problem hiding this comment.
Again, repeatability; depending on the type of map (array-map vs. hash-map, etc.) this order of all this could shift dramatically; for small maps it's in order of keys added, in larger maps (hash-map) it's related to the hash of the key.
I'd say a good fixed order would be:
- directive defs
- scalars
- enums
- unions
- interfaces
- input-objects
- objects (including Query, Mutation, etc., rolled in)
There was a problem hiding this comment.
Sorting has been added to reflect reviews.
There was a problem hiding this comment.
Another problem I'm just noticing is that the extras directives, types, etc. provided by com.walmartlabs.lacinia.federation/foundation-types need to be filtered back out.
| :mutations (edn-mutations->sdl-mutations val) | ||
| :enums (edn-enums->sdl-enums val) | ||
| :directive-defs (edn-directive-defs->sdl-directives val) | ||
| :roots ""))) |
There was a problem hiding this comment.
Roots could be important, though my experience with Apollo is that it's fragile if the service schemas don't agree on the names of the root objects. That may have changed since I looked at it > 1 year ago.
There was a problem hiding this comment.
Well, I don't understand what you mean, can you elaborate on that?
There was a problem hiding this comment.
In the SDL you can override the default names of the Query, Mutation, and Subscription objects using the schema keyword (https://spec.graphql.org/October2021/#sec-Schema).
So this code must honor that, but must also (as necessary) emit the schema content into the output SDL.
There was a problem hiding this comment.
Oh, I didn't know there was such a grammar. reflected.
hlship
left a comment
There was a problem hiding this comment.
As I understand the Apollo federation documentation, the @extends and other directive, scalar types, etc. are not explicit in the input SDL but still available, and should not be generated into the output SDL. In the systems I've developed under federation, we start with SDL document and provided that document, as is ... you can see that in the code in master.
| (nil? hd) "" | ||
| (= 'non-null hd) (str (apply-list edn-type->sdl-type tl) "!") | ||
| (= 'list hd) (str "[" (apply-list edn-type->sdl-type tl) "]") | ||
| (= 'String hd) "String" |
There was a problem hiding this comment.
These special cases would also be caught by the symbol? case below.
| "Translate the edn lacinia schema to the SDL schema." | ||
| [schema] | ||
| (->> schema | ||
| (map (fn [[key val]] |
There was a problem hiding this comment.
Another problem I'm just noticing is that the extras directives, types, etc. provided by com.walmartlabs.lacinia.federation/foundation-types need to be filtered back out.
I am not sure if I understand the review comment well, but if you look at the document about apollo's federation subgraph, it says that the server should provide some schemas. Then shouldn't the schema be exposed to the router through query{_service{sdl}}}? |
|
I'll work on resolving this against the Apollo documentation. |
|
Federation is a moving target, we're compatible with 1.0, but 2.0 changes things: https://www.apollographql.com/docs/federation/federated-types/federated-directives In any case, I don't think the current version of this code will work because it includes the Federation (1.0) annotations and objects injected into the schema. In the current version, based on reading SDL, you can see that those elements aren't in the input SDL (they are provided after that is parsed) and then we use the input SDL as-is when exposing the schema to the Apollo gateway. I don't know exactly what would happen if we include those elements in the generated SDL but I suspect Apollo will reject the schema. |
|
I'm struggling to find time to come back and finish reviewing this. I want to test what happens when the injected Fed 1.0 directives and types are not filtered out when generating SDL from the schema (that is, see how Apollo reacts). |
|
I'm starting to work through the backlog of Lacinia PRs and I'm curious if you can continue working on this to resolve deps.edn conflicts? |
Extends lacinia's support for federation to add the ability to support federation through the edn schema as well.